把常用的顏色、間距、字型、邊角半徑集中管理:
<Window.Resources>
    <!-- 調色盤 -->
    <Color x:Key="PrimaryColor">#FF2B6CB0</Color>
    <Color x:Key="AccentColor">#FF0EA5E9</Color>
    <SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource PrimaryColor}"/>
    <SolidColorBrush x:Key="AccentBrush" Color="{StaticResource AccentColor}"/>
    <SolidColorBrush x:Key="TextBrush" Color="#222222"/>
    <SolidColorBrush x:Key="MutedTextBrush" Color="#666666"/>
    <SolidColorBrush x:Key="PanelBrush" Color="#F7F9FC"/>
    <!-- 間距與圓角 -->
    <x:Double x:Key="Radius">6</x:Double>
    <Thickness x:Key="Gap">12</Thickness>
    <Thickness x:Key="CellPadding">6,4</Thickness>
    <!-- 字型大小 -->
    <x:Double x:Key="TitleSize">20</x:Double>
    <x:Double x:Key="BodySize">14</x:Double>
</Window.Resources>
StaticResource:載入時解析,效能較佳;適用較少變化的資源。DynamicResource:執行期可變更(例如切換 Light/Dark 主題)。<Window.Resources>
    <Style x:Key="PrimaryButton" TargetType="Button">
        <Setter Property="Background" Value="{StaticResource PrimaryBrush}"/>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Padding" Value="12,8"/>
        <Setter Property="FontSize" Value="{StaticResource BodySize}"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Cursor" Value="Hand"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Background="{TemplateBinding Background}"
                            CornerRadius="{StaticResource Radius}">
                        <ContentPresenter HorizontalAlignment="Center"
                                          VerticalAlignment="Center"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="PART_Border" Property="Background" 
                                    Value="{StaticResource AccentBrush}"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Opacity" Value="0.5"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<!-- 使用 -->
<Button Style="{StaticResource PrimaryButton}" Content="下載股票"/>
注意:若在
ControlTemplate使用Border並需要觸發器指到該元素,請給它x:Name="PART_Border",上例可再補上 Name 後於 Trigger 使用TargetName。
對指定型別全域生效、無需 x:Key:
<Window.Resources>
    <Style TargetType="TextBox">
        <Setter Property="Margin" Value="0,0,0,8"/>
        <Setter Property="Padding" Value="8,6"/>
        <Setter Property="FontSize" Value="{StaticResource BodySize}"/>
        <Setter Property="BorderBrush" Value="#DDDDDD"/>
        <Setter Property="BorderThickness" Value="1"/>
    </Style>
</Window.Resources>
<!-- 所有 TextBox 都會套用 -->
<TextBox Text="{Binding Query}" />
專案結構建議:
/Styles
   Colors.xaml
   Typography.xaml
   Controls.Buttons.xaml
   Controls.DataGrid.xaml
   Theme.Light.xaml
   Theme.Dark.xaml
在 App.xaml 合併:
<Application ...>
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Styles/Colors.xaml"/>
                <ResourceDictionary Source="Styles/Typography.xaml"/>
                <ResourceDictionary Source="Styles/Controls.Buttons.xaml"/>
                <ResourceDictionary Source="Styles/Controls.DataGrid.xaml"/>
                <ResourceDictionary Source="Styles/Theme.Light.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
好處:集中資源、跨視窗共用、切換主題更容易。
建立 Styles/Controls.DataGrid.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!-- 行為一致化 -->
    <Style TargetType="DataGrid">
        <Setter Property="AutoGenerateColumns" Value="False"/>
        <Setter Property="HeadersVisibility" Value="Column"/>
        <Setter Property="GridLinesVisibility" Value="None"/>
        <Setter Property="RowHeaderWidth" Value="0"/>
        <Setter Property="CanUserAddRows" Value="False"/>
        <Setter Property="CanUserDeleteRows" Value="False"/>
        <Setter Property="CanUserReorderColumns" Value="True"/>
        <Setter Property="CanUserResizeColumns" Value="True"/>
        <Setter Property="CanUserSortColumns" Value="True"/>
        <Setter Property="RowBackground" Value="White"/>
        <Setter Property="AlternatingRowBackground" Value="#FAFAFA"/>
        <Setter Property="RowHeight" Value="32"/>
        <Setter Property="ColumnHeaderHeight" Value="36"/>
        <Setter Property="HorizontalGridLinesBrush" Value="#EEEEEE"/>
        <Setter Property="VerticalGridLinesBrush" Value="#EEEEEE"/>
        <Setter Property="Foreground" Value="{StaticResource TextBrush}"/>
        <Setter Property="BorderBrush" Value="#E6EAF0"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="CellStyle">
            <Setter.Value>
                <Style TargetType="DataGridCell">
                    <Setter Property="Padding" Value="{StaticResource CellPadding}"/>
                    <Setter Property="BorderThickness" Value="0"/>
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="ColumnHeaderStyle">
            <Setter.Value>
                <Style TargetType="DataGridColumnHeader">
                    <Setter Property="FontWeight" Value="SemiBold"/>
                    <Setter Property="Foreground" Value="{StaticResource MutedTextBrush}"/>
                    <Setter Property="Background" Value="{StaticResource PanelBrush}"/>
                    <Setter Property="Padding" Value="8,4"/>
                    <Setter Property="BorderBrush" Value="#E6EAF0"/>
                    <Setter Property="BorderThickness" Value="0,0,0,1"/>
                </Style>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
使用時只要宣告 DataGrid,樣式會自動套用(隱式樣式)。
DropShadowEffect(慎用,成本高),或用背景/邊框營造層級。建立 Theme.Light.xaml 與 Theme.Dark.xaml 兩套資源,只差在顏色刷子值:
Theme.Light.xaml:
<SolidColorBrush x:Key="WindowBgBrush" Color="#FFFFFF"/>
<SolidColorBrush x:Key="TextBrush" Color="#222222"/>
<SolidColorBrush x:Key="PanelBrush" Color="#F7F9FC"/>
Theme.Dark.xaml:
<SolidColorBrush x:Key="WindowBgBrush" Color="#1F2430"/>
<SolidColorBrush x:Key="TextBrush" Color="#EAEAEA"/>
<SolidColorBrush x:Key="PanelBrush" Color="#2A3040"/>
切換主題(程式碼側)做法:
Application.Current.Resources.MergedDictionaries 最後一筆主題資源。DynamicResource 綁定顏色處處即時更新)。<DockPanel Background="{DynamicResource WindowBgBrush}">
    <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="{StaticResource Gap}">
        <TextBox Width="220" />
        <Button Style="{StaticResource PrimaryButton}" Content="下載股票" Margin="8,0,0,0"/>
        <Button Content="載入本地" Margin="8,0,0,0"/>
    </StackPanel>
    <DataGrid ItemsSource="{Binding Stocks}" Margin="{StaticResource Gap}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="代號" Binding="{Binding Code}" Width="100"/>
            <DataGridTextColumn Header="名稱" Binding="{Binding Name}" Width="200"/>
            <DataGridTextColumn Header="產業" Binding="{Binding Industry}" Width="*"/>
        </DataGrid.Columns>
    </DataGrid>
</DockPanel>
MergedDictionaries 中被替換,而非在控制項本地覆蓋。Style 統一控制項外觀,抽離到 ResourceDictionary。DynamicResource 即時換膚。